﻿using BattleFury.Lib.Network.Events;
using BattleFury.Lib.Network.Packets;
using Lidgren.Network;
using System;
using System.ComponentModel;
using System.Text;
using System.Threading;

namespace BattleFury.Lib.Network
{
    public class NetworkClient
    {
        #region Properties

        private NetClient _client;
        private BackgroundWorker _listener;
        private bool _isRunning;
        private StringBuilder _outputBuffer;

        public string Host { get; private set; }
        public int Port { get; private set; }
        public string AppIdentifier { get; private set; }
        public NetConnectionStatus Status { get; set; }

        public bool IsRunning
        {
            get { return _isRunning; }
        }

        public event EventHandler<MessageReceivedEventArgs> OnMessageReceived;

        #endregion

        #region Initialization

        public NetworkClient(string appIdentifier, string host, int port)
        {
            Host = host;
            Port = port;
            AppIdentifier = appIdentifier;
            _isRunning = false;
        }

        #endregion

        #region Actions

        public void Connect()
        {
            _outputBuffer = new StringBuilder();

            var config = new NetPeerConfiguration(AppIdentifier);
            _client = new NetClient(config);

            _listener = new BackgroundWorker
            {
                WorkerReportsProgress = true
            };
            _listener.DoWork += DoWork;
            _listener.ProgressChanged += ReportProgress;
            _listener.RunWorkerAsync();

            try
            {
                _isRunning = true;
                _client.Start();

                var handshake = _client.CreateMessage("~HANDSHAKE~");
                _client.Connect(Host, Port, handshake);

                Status = NetConnectionStatus.Connected;
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                _isRunning = false;
                _client.Disconnect(e.Message);
            }
        }

        public void Disconnect()
        {
            if (Status != NetConnectionStatus.Connected) return;
            _client.Shutdown("Disconnecting");
            Status = NetConnectionStatus.Disconnected;
        }

        //public void Send(Packet packet)
        //{
        //    var msg = _client.CreateMessage(packet.ToBase64());
        //    _client.SendMessage(msg, NetDeliveryMethod.ReliableOrdered);
        //    _client.FlushSendQueue();
        //}

        public void SendPacket(IPacket packet)
        {
            var msg = packet.ToOutgoingMessage(_client);
            _client.SendMessage(msg, packet.NetDeliveryMethod);
            _client.FlushSendQueue();
        }

        #endregion

        #region Methods

        private void ReportProgress(object sender, ProgressChangedEventArgs progressChangedEventArgs)
        {
            if (_outputBuffer.Length > 0)
            {
                SendConsoleMessage(_outputBuffer.ToString());
                _outputBuffer.Clear();
            }

            ProcessEvents();
        }

        private void ProcessEvents()
        {

        }

        private void DoWork(object sender, DoWorkEventArgs e)
        {
            while (_isRunning)
            {
                NetIncomingMessage msg;
                while ((msg = _client.ReadMessage()) != null)
                {
                    switch (msg.MessageType)
                    {
                        case NetIncomingMessageType.DebugMessage:
                        case NetIncomingMessageType.ErrorMessage:
                        case NetIncomingMessageType.WarningMessage:
                        case NetIncomingMessageType.VerboseDebugMessage:
                            var text = msg.ReadString();
                            _outputBuffer.Append("MSG: " + text);
                            break;
                        case NetIncomingMessageType.StatusChanged:
                            var status = (NetConnectionStatus)msg.ReadByte();
                            var reason = msg.ReadString();
                            _outputBuffer.Append("SC: " + reason);
                            break;
                        case NetIncomingMessageType.Data:
                            var data = msg.ReadString();
                            _outputBuffer.Append("DATA: " + data);
                            break;
                        default:
                            var output = msg.ReadString();
                            _outputBuffer.Append("DEF: " + output);
                            break;
                    }
                    _client.Recycle(msg);
                    _listener.ReportProgress(0);
                    Thread.Sleep(1);
                }
            }
        }

        #endregion

        #region Event Handlers

        private void SendConsoleMessage(string message)
        {
            if (OnMessageReceived == null) return;
            var args = new MessageReceivedEventArgs()
            {
                Message = message
            };
            OnMessageReceived(this, args);
        }

        #endregion

        //private void ReceiveMessage(object peer)
        //{
        //	NetIncomingMessage im;
        //	while ((im = _client.ReadMessage()) != null)
        //	{
        //		// handle incoming message
        //		switch (im.MessageType)
        //		{
        //			case NetIncomingMessageType.DebugMessage:
        //			case NetIncomingMessageType.ErrorMessage:
        //			case NetIncomingMessageType.WarningMessage:
        //			case NetIncomingMessageType.VerboseDebugMessage:
        //				string text = im.ReadString();
        //				//Output(text);
        //				break;
        //			case NetIncomingMessageType.StatusChanged:
        //				NetConnectionStatus status = (NetConnectionStatus)im.ReadByte();

        //				//if (status == NetConnectionStatus.Connected)
        //					//_form.EnableInput();
        //				//else
        //					//s_form.DisableInput();

        //				//if (status == NetConnectionStatus.Disconnected)
        //					//s_form.button2.Text = "Connect";

        //				var reason = im.ReadString();
        //				//Output(status.ToString() + ": " + reason);

        //				break;
        //			case NetIncomingMessageType.Data:
        //				string chat = im.ReadString();
        //				//Output(chat);
        //				break;
        //			default:
        //				//Output("Unhandled type: " + im.MessageType + " " + im.LengthBytes + " bytes");
        //				break;
        //		}
        //	}
        //}
    }
}